package io.netty;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;

import com.alibaba.fastjson.JSON;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.rtcdemo.RtcData;
import io.netty.util.AttributeKey;

public class WebSocketHandler extends ChannelInboundHandlerAdapter {

	static Map<String, Channel> sockets=new HashMap<>();
	static Map<String, Set<Channel>> rooms=new HashMap<>();
	static Map<String, BiConsumer<Map, Channel>>  functions=new HashMap<>();
	static  final AttributeKey<String> ROOM = AttributeKey.valueOf("room");
	 
	public WebSocketHandler() {
	
		
		functions.put("__join", this::channelJoin);
		functions.put("__ice_candidate", this::channelIceCandidate);
		functions.put("__offer", this::socketOffer);
		functions.put("__answer", this::socketAnswer);
		
	}
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
		Channel channel=ctx.channel();
		System.out.println("用户上线: " + ctx.channel().id().asLongText());
		sockets.put(channel.id().asLongText(), channel);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {

		System.out.println("用户下线: " + ctx.channel().id().asLongText());
		super.channelInactive(ctx);
		channelRemovePeer(ctx.channel());
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

		if (!(msg instanceof TextWebSocketFrame)) {
			ctx.channel().writeAndFlush(new TextWebSocketFrame("来自服务端: 不支持" + LocalDateTime.now()));
			return;
		}
		
		
		TextWebSocketFrame textWebSocketFrame=(TextWebSocketFrame)msg;
		String jsonStr=textWebSocketFrame.text();
		System.out.println("--recv->"+jsonStr);
		RtcData rtcData=JSON.parseObject(jsonStr,RtcData.class);
		
		String eventName=null;
		if(rtcData.getEventName()!=null) {
			eventName=rtcData.getEventName();
		}
		
		if(functions.containsKey(eventName)) {
			functions.get(eventName).accept(rtcData.getData(), ctx.channel());
		}else {
			System.out.println("不支持事件"+eventName);
		}


	}

	
	
	private void channelJoin(Map<String, Object> data,Channel socket) {
	
	
		System.out.println(sockets.size());
		Set<String> ids=new HashSet<>();
	
		String socketId=socket.id().asLongText();
		String room="__default";
		Set<Channel> curRoom=null;
		
		if(socket.hasAttr(ROOM)) {
			room=socket.attr(ROOM).get();
		}
		
		if(rooms.containsKey(room)) {
			curRoom=rooms.get(room);
			
			RtcData sendOut=new RtcData();
			sendOut.setEventName("_new_peer");
			Map<String, Object> sendData=new HashMap<>();
			sendData.put("socketId", socketId);
			sendOut.setData(sendData);
			
			curRoom.forEach((Channel curSocket)->{
				String curtSocId=curSocket.id().asLongText();
				if(!curtSocId.equals(socketId)) {
					curSocket.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendOut)));
					ids.add(curSocket.id().asLongText());
				}
				
			});
		}else {
			curRoom=new HashSet<>();
			rooms.put(room, curRoom);
		}
		
		
		curRoom.add(socket);
		socket.attr(ROOM).set(room);
	
		RtcData sendOut=new RtcData();
		sendOut.setEventName("_peers");
		Map<String, Object> sendData=new HashMap<>();
		sendData.put("connections", JSON.toJSON(ids));
		sendData.put("you",  socketId);
		sendOut.setData(sendData);

		socket.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendOut)));
		System.out.println(socketId+"加入房间"+room+JSON.toJSONString(sendOut));
	
	}
	
	
	private void  channelRemovePeer(Channel socket) {
		
		/**
		 * var i, m,
			room = socket.room,
			curRoom;
		if (room) {
			curRoom = that.rooms[room];
			for (i = curRoom.length; i--;) {
				if (curRoom[i].id === socket.id) {
					continue;
				}
				curRoom[i].send(JSON.stringify({
					"eventName": "_remove_peer",
					"data": {
						"socketId": socket.id
					}
				}), errorCb);
			}
		}

		that.removeSocket(socket);

		 */
		Set<Channel> curRoom=null;
		String socketId=socket.id().asLongText();
		
		String room=socket.attr(ROOM).get();
		if(room!=null) {
			curRoom=rooms.get(room);
		}
		
		if(curRoom!=null) {
			
			curRoom.remove(socket);
			
			RtcData sendOut=new RtcData();
			sendOut.setEventName("_remove_peer");
			Map<String, Object> sendData=new HashMap<>();
			sendData.put("socketId", socketId);
			sendOut.setData(sendData);
			
			curRoom.forEach((curSocket)->{
				String curtSocId=curSocket.id().asLongText();
				if(!curtSocId.equals(socketId)) {
					curSocket.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendOut)));
				}
				
			});
		}
		
	}
	
	private void channelIceCandidate(Map<String, Object> data,Channel socket) {
		
		/**
		 * var soc = this.getSocket(data.socketId);

		if (soc) {
			soc.send(JSON.stringify({
				"eventName": "_ice_candidate",
				"data": {
					"label": data.label,
					"candidate": data.candidate,
					"socketId": socket.id
				}
			}), errorCb);

			this.emit('ice_candidate', socket, data);
		}
		 */
		Channel soc=null;
		if(data.containsKey("socketId")) {
			soc=sockets.get(data.get("socketId"));
		}
		
		
		if(soc!=null) {
			
			RtcData sendOut=new RtcData();
			sendOut.setEventName("_ice_candidate");

			Map<String, Object> sendData=new HashMap<>();
			sendData.put("label", data.get("label"));
			sendData.put("candidate", data.get("candidate"));
			sendData.put("socketId", socket.id().asLongText());
			sendOut.setData(sendData);
			soc.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendOut)));
		}
		System.out.println("接收到来自" + socket.id().asLongText() + "的ICE Candidate");
	}
	
	
	
	private void socketOffer(Map<String, Object> data,Channel socket) {
		
		/**
		 * var soc = this.getSocket(data.socketId);

		if (soc) {
			soc.send(JSON.stringify({
				"eventName": "_offer",
				"data": {
					"sdp": data.sdp,
					"socketId": socket.id
				}
			}), errorCb);
		}
		this.emit('offer', socket, data);
		 * 
		 */
		Channel soc=null;
		if(data.containsKey("socketId")) {
			soc=sockets.get(data.get("socketId"));
		}
		
		
		if(soc!=null) {
			
			RtcData sendOut=new RtcData();
			sendOut.setEventName("_offer");
			Map<String, Object> sendData=new HashMap<>();
			sendData.put("sdp", data.get("sdp"));
			sendData.put("socketId", socket.id().asLongText());
			sendOut.setData(sendData);
			soc.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendOut)));
		}
		
		System.out.println("接收到来自" + socket.id().asLongText() + "的Offer");
	
	}
	
	private void socketAnswer(Map<String, Object> data,Channel socket) {
		
		/**
		 * var soc = this.getSocket(data.socketId);
		if (soc) {
			soc.send(JSON.stringify({
				"eventName": "_answer",
				"data": {
					"sdp": data.sdp,
					"socketId": socket.id
				}
			}), errorCb);
			this.emit('answer', socket, data);
		}
		 */
		
		Channel soc=null;
		if(data.containsKey("socketId")) {
			soc=sockets.get(data.get("socketId"));
		}
		
		
		if(soc!=null) {
			
			RtcData sendOut=new RtcData();
			sendOut.setEventName("_answer");
			Map<String, Object> sendData=new HashMap<>();
			sendData.put("sdp", data.get("sdp"));
			sendData.put("socketId", socket.id().asLongText());
			sendOut.setData(sendData);
			soc.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendOut)));
		}
		
		System.out.println("接收到来自" + socket.id().asLongText() + "的answer");
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		
		cause.printStackTrace();
		ctx.channel().close();
	}
}